import java.io.RandomAccessFile;

public class base64
{ static final char b64en[]=
  { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/',
  };
  static final byte b64de[]=new byte[256];
  static
  { for (byte i=0;i<b64en.length;++i)
    { b64de[(byte)b64en[i]]=i; }
  };

  static final char b64pad='=';
  static final String b64ln="\r\n";

  static String base64en(byte[] buf)
  { StringBuffer res; int a,i,j,k;
    j=buf.length; k=(j/3)*3;
    res=new StringBuffer((k+1)*4+(k/48+1)<<1);

    for (i=0;i<k;)
    { if (i!=0 && i%48==0) res.append(b64ln);
      a=(b2i(buf[i++])<<16)|(b2i(buf[i++])<<8)|(b2i(buf[i++]));
      res.append(b64en[(a>>18)&63]);
      res.append(b64en[(a>>12)&63]);
      res.append(b64en[(a>>6)&63]);
      res.append(b64en[(a)&63]);
    }
    if (i!=0 && i%48==0) res.append(b64ln);
    if (i+1==j)
    { a=(b2i(buf[i++])<<16);
      res.append(b64en[(a>>18)&63]);
      res.append(b64en[(a>>12)&63]);
      res.append(b64pad);
      res.append(b64pad);
    } else
    if (i+2==j)
    { a=(b2i(buf[i++])<<16)|(b2i(buf[i++])<<8);
      res.append(b64en[(a>>18)&63]);
      res.append(b64en[(a>>12)&63]);
      res.append(b64en[(a>>6)&63]);
      res.append(b64pad);
    }
    res.append(b64ln);

    return (res.toString());
  };

  static byte[] base64de(String buf0)
  { byte[] buf1,buf2;

    buf0=strip(buf0,"\r\n");
    buf1=buf0.getBytes();
    int i,j=buf1.length,k=(j/4)*3;
    if (j>0 && buf1[j-1]==(byte)b64pad) { --j; --k; }
    if (j>0 && buf1[j-1]==(byte)b64pad) { --j; --k; }
    buf2=new byte[k]; int e1=0;

    for (i=k=0;i<j;)
    { e1<<=6; e1|=b64de[buf1[i]];
      if ((++i&3)==0)
      { buf2[k++]=(byte)((e1>>16)&0xFF);
        buf2[k++]=(byte)((e1>>8) &0xFF);
        buf2[k++]=(byte)((e1>>0) &0xFF);
        e1=0;
      }
    }
    if ((i&3)==2)
    { buf2[k++]=(byte)((e1>>4) &0xFF);
    } else
    if ((i&3)==3)
    { buf2[k++]=(byte)((e1>>10)&0xFF);
      buf2[k++]=(byte)((e1>>2) &0xFF);
    }

    return (buf2);
  };

  static int b2i(byte b)
  { return (((int)b)&255);
  };

  static String strip(String s,char ch)
  { int i,j=s.length();
    StringBuffer res=new StringBuffer(j);

    for (i=0;i<j;++i)
    { char chi=s.charAt(i);
      if (chi!=ch) res.append(chi);
    }
    return (res.toString());
  };

  static String strip(String s,String ch)
  { int i,j=s.length();
    StringBuffer res=new StringBuffer(j);

    for (i=0;i<j;++i)
    { char chi=s.charAt(i);
      if (ch.indexOf(chi)==-1) res.append(chi);
    }
    return (res.toString());
  };

  public static void main(String[] args)
  { boolean enc=false;

    if (args.length!=3)
    { System.out.println("Args: enc|dec <in_file> <out_file>");
      System.exit(-1);
    }

    if (args[0].equals("enc")) enc=true; else
    if (args[0].equals("dec")) enc=false; else
    { System.out.println("Error: Invalid command");
      System.exit(-1);
    }

    try
    { RandomAccessFile f1,f2;
      f1=new RandomAccessFile(args[1],"r");
      f2=new RandomAccessFile(args[2],"rw");
      byte[] buf=new byte[(int)f1.length()];
      f1.read(buf); byte[] buf2;
      if (enc)
      { buf2=base64en(buf).getBytes();
      } else
      { buf2=base64de(new String(buf));
      }
      f2.write(buf2);
      f1.close(); f2.close();
    } catch (Exception e)
    { System.out.println("Error: "+e.toString());
      System.exit(-1);
    }
  };
};
